package fatworm.planner;

import fatworm.server.Fatworm;
import fatworm.storage.table.Schema;
import fatworm.tx.Transaction;
import fatworm.concept.*;
import fatworm.concept.DataType.SqlValue;
import fatworm.concept.datatype.*;
import fatworm.parser.syntree.*;
import fatworm.query.*;
import fatworm.query.constant.*;
import fatworm.storage.types.Types;

public class BasicUpdatePlanner implements UpdatePlanner {
	
	public int execute(SyntaxNode node, Transaction tx) {
		if (node instanceof DeleteTableNode) 
			return executeDelete((DeleteTableNode)node, tx);
		else if (node instanceof UpdateTableNode) 
			return executeModify((UpdateTableNode)node, tx);
		else if (node instanceof InsertTableNode) 
			return executeInsert((InsertTableNode)node, tx);
		else if (node instanceof CreateTableNode)
			return executeCreateTable((CreateTableNode)node, tx);
		else if (node instanceof CreateDBNode) 
			return executeCreateDB((CreateDBNode)node);
		else if (node instanceof DropDBNode) 
			return executeDropDB((DropDBNode)node);
		else if (node instanceof UseDBNode) 
			return executeUseDB((UseDBNode)node);
		
		return 0;
	}
	
	public int executeUseDB(UseDBNode node) {
		Fatworm.useDB(node.name);
		return 0;
	}
	
	public int executeDropDB(DropDBNode node) {
		Fatworm.dropDB(node.name);
		return 0;
	}
	
	public int executeCreateDB(CreateDBNode node) {
		Fatworm.createDB(node.name);
		return 0;
	}
   
	public int executeDelete(DeleteTableNode node, Transaction tx) {
		Translator translator = new Translator(tx);
		Plan p = new TablePlan(node.tableName, tx);
		p = new SelectPlan(p, new Predicate(translator.convert(node.where)));
		UpdateScan us = (UpdateScan) p.open();
		int count = 0;
		while(us.next()) {
			us.delete();
			count++;
		}
		us.close();
		return count;
	}
   
	public int executeModify(UpdateTableNode node, Transaction tx) {
		Translator translator = new Translator(tx);
		Plan p = new TablePlan(node.tableName, tx);
		p = new SelectPlan(p, new Predicate(translator.convert(node.where)));
		UpdateScan us = (UpdateScan) p.open();
		int count = 0;
		while(us.next()) {
			for (int i = 0; i < node.setList.size(); i++) {
				Constant val = translator.convert(node.setList.get(i).value).evaluate(us);  
				us.setVal(node.setList.get(i).fieldName, val);
			}
			count++;
		}
		us.close();
		return count;
	}
   
	public int executeInsert(InsertTableNode node, Transaction tx) {
		Translator translator = new Translator(tx);
		Plan p = new TablePlan(node.tableName, tx);
		UpdateScan us = (UpdateScan) p.open();
		us.insert();
		
		
		if (node.fieldlist == null) {
			int i = 0;
			for (String fldname : p.getSchema().fields()) {
				Constant val = translator.convert(node.values.get(i++)).evaluate(us);
				us.setVal(fldname, val);
			}
		}
		else
			for (int i = 0; i < node.fieldlist.size(); i++) {
				Constant val = translator.convert(node.values.get(i)).evaluate(us);
				us.setVal(node.fieldlist.get(i), val);
			}
		us.close();
		return 1;
	}
   
	public int executeCreateTable(CreateTableNode node, Transaction tx) {
		Schema sch = new Schema();
		for (DataField df : node.columns) {
			String name = df.getName();
			DataType dt = df.getType();
			SqlValue def = df.getDefaultValue();
			Constant c = null;
			
			if (def instanceof FatBoolean.BooleanValue)
				c = new BooleanConstant(((FatBoolean.BooleanValue)def).value);
			else if (def instanceof FatInt.IntValue)
				c = new IntConstant(((FatInt.IntValue)def).value);
			else if (def instanceof FatString.StringValue) 
				c = new StringConstant(((FatString.StringValue)def).value);
			else if (def instanceof FatFloat.FloatValue)
				c = new FloatConstant(((FatFloat.FloatValue)def).value);
			else if (def instanceof FatDateTime.DateTimeValue)
				c = new DateConstant(((FatDateTime.DateTimeValue)def).value.toString());
			else
				c = new NullConstant();
			
			switch (dt.getTypeKey()) {
				case DataType.T_BOOLEAN   : sch.addField(name, Types.BOOLEAN, -1, c);
				                            break;
				case DataType.T_CHAR      : sch.addField(name, Types.CHAR, ((FatCharArray)dt).getMaxLength(), c);
											break;
				case DataType.T_DATETIME  : sch.addField(name, Types.DATETIME, -1, c);
											break;
				case DataType.T_DECIMAL   : sch.addField(name, Types.DECIMAL, ((FatDecimal)dt).getMaxLength(), c);
											break;
				case DataType.T_FLOAT     : sch.addField(name, Types.FLOAT, -1, c);
											break;
				case DataType.T_INT       : sch.addField(name, Types.INT, -1, c);
											break;
				case DataType.T_TIMESTAMP : sch.addField(name, Types.TIMESTAMP, -1, c);
											break;
				case DataType.T_VARCHAR   : sch.addField(name, Types.VARCHAR, ((FatVarchar)dt).getMaxLength(), c);
											break;
				default : continue;
			}
		}
		Fatworm.mdMgr().createTable(node.tableName, sch, tx);
		return 0;
	}
   
   //TODO  index
/*   public int executeCreateIndex(CreateIndexNode node, Transaction tx) {
      SimpleDB.mdMgr().createIndex(data.indexName(), data.tableName(), data.fieldName(), tx);
      return 0;  
   }*/
}
